from collections.abc import Callable
from pathlib import Path
from sys import stderr
from typing import Any

from pydantic import BaseModel
from pydantic_settings import BaseSettings, SettingsConfigDict

from app.core.handlers.request_context import request_context

PROJECT_ROOT: Path = Path(__file__).parent.parent.parent

LOG_DIR: Path = PROJECT_ROOT.joinpath("logs")
# 确保日志目录存在
LOG_DIR.mkdir(parents=True, exist_ok=True)

# 日志配置
# [2025-09-02 10:52:38.908][INFO][model.func:line][request_id][ip|method|path] - msg
LOG_FORMAT: str = (
    "<green>[{time:YYYY-MM-DD HH:mm:ss.SSS}]</green>"
    "<level>[{level}]</level>"
    "<blue>[{module}.{function}:{line}]</blue>"
    "<magenta>[{extra[request_id]}]</magenta>"
    "<cyan>[{extra[request_ip]}|{extra[request_method]}|{extra[request_path]}]</cyan> - "
    "<level>{message}</level>"
)


def wrapper_filter(modules: list) -> Callable:
    def _filter(record):
        extra = record["extra"]
        extra["request_id"] = request_context.get("request_id")
        extra["request_ip"] = request_context.get("request_ip")
        extra["request_method"] = request_context.get("request_method")
        extra["request_path"] = request_context.get("request_path")
        return record["extra"]["module"] in modules or "any" in modules

    return _filter


class DatabaseConfig(BaseModel):
    url: str
    engine_options: dict[str, Any] | None = None


class JWTConfig(BaseModel):
    secret_key: str
    access_token_expire_minutes: int
    refresh_token_expire_minutes: int
    algorithm: str


LOGURU_HANDLERS: list[dict[str, Any]] = [
    {
        "sink": stderr,
        "format": LOG_FORMAT,
        "level": "DEBUG",
        "enqueue": False,
        "filter": wrapper_filter(["app", "any"]),
    },
    {
        "sink": LOG_DIR.joinpath("app.log"),
        "format": LOG_FORMAT,
        "rotation": "1 week",
        "retention": "10 days",
        "level": "INFO",
        "enqueue": False,
        "filter": wrapper_filter(["app"]),
    },
    {
        "sink": LOG_DIR.joinpath("error.log"),
        "format": LOG_FORMAT,
        "rotation": "1 week",
        "retention": "10 days",
        "level": "ERROR",
        "enqueue": False,
        "filter": wrapper_filter(["app"]),
    },
]

LOGURU_EXTRA: dict[str, Any] = {
    "module": "-",
    "request_id": "-",
    "request_ip": "-",
    "request_method": "-",
    "request_path": "-",
}


class LoguruConfig(BaseModel):
    handlers: list[dict[str, Any]]
    extra: dict[str, Any]


class Settings(BaseSettings):
    model_config = SettingsConfigDict(
        env_file="../.env", env_ignore_empty=True, extra="ignore", env_prefix="FA_"
    )
    # 通用配置
    api_v1_str: str = "/api/v1"

    project_name: str

    project_root: str = str(PROJECT_ROOT)

    debug: bool = False

    # 数据库配置
    database_url: str = "mysql+pymysql://root:Guiaiy857203@localhost:3306/fastapi-admin"

    @property
    def database_config(self) -> DatabaseConfig:
        return DatabaseConfig(url=self.database_url)

    # 日志配置
    @property
    def loguru_config(self) -> LoguruConfig:
        return LoguruConfig(handlers=LOGURU_HANDLERS, extra=LOGURU_EXTRA)

    # 安全配置
    secret_key: str = "K7Gj!9#Lm$2@vXpR*5&nQwYtZ8^uIwOe"
    access_token_expire_minutes: int = 60 * 24
    refresh_token_expire_minutes: int = 60 * 24 * 7
    algorithm: str = "HS256"

    # JWT配置
    @property
    def jwt_config(self) -> JWTConfig:
        return JWTConfig(
            secret_key=self.secret_key,
            access_token_expire_minutes=self.access_token_expire_minutes,
            refresh_token_expire_minutes=self.refresh_token_expire_minutes,
            algorithm=self.algorithm,
        )

    # 敏感字段
    sensitive_field: list[str] = ["password", "token", "access_token", "refresh_token"]


# 优先级
# 1.显式传递给类的参数（如 AppSettings(xxx=xxx)）
# 2.环境变量（如 FA_xxx=xxx）
# 3. .env 文件中的变量
# 4.类字段的默认值
settings = Settings(project_name="FastAPI Admin")